/***************************************************************************
 * Open Object Oriented ANSI C                                             *
 ***************************************************************************
 * Code given under the terms of GNU General Public Licence (GPLv3)        *
 * and without any waranties of any kind including but not limitative to   *
 * waranties on merchandability or any particular applications fitness.    *
 * For more information on GNU/GPL go on :                                 *
 * "http://www.gnu.org/copyleft/gpl.html"                                  *
 *                                                                         *
 * You are allowed to use it for any purposes in the terms of GNU/GPLv3    *
 * (or more).                                                              *
 * This text MUST stay in state on copyed sources (or sources using it)    *
 * and must not be altered.                                                *
 * You are allowed to add your name at the end of the Copylefs list.       *
 ***************************************************************************
 * Copylefts List :                                                        *
 ***************************************************************************
 * 2010-04-16 Patrick PIGNOL <pignol_patrick@hotmail.com> (Original)       *
 * (Type your name here if needed)                                         *
 ***************************************************************************/
#include <signal.h>
#include "EventDelegate.h"
#include "Class.h"
#include "ExceptionManager.h"

static EventDelegateVirtualTable* EventDelegateVirtualTableInstance = 0;

EventDelegate* EventDelegateNew(unsigned long pArgsCount, va_list* pParameters)
{
    EventDelegate* this;
    this = (EventDelegate*) malloc(sizeof(EventDelegate));
    if(!this)
    {
        raise(SIGABRT);
    }
    this->VirtualTable = EventDelegateInitialize(this, pArgsCount, pParameters);
    this->Constructor = EventDelegateConstructor;
    this->Destructor = EventDelegateDestructor;
    this->Clone = EventDelegateClone;
    this->Handle = EventDelegateHandle;
    return this;
}

EventDelegateVirtualTable* EventDelegateInitialize(EventDelegate* this, unsigned long pArgsCount, va_list* pParameters)
{
    if(!EventDelegateVirtualTableInstance)
    {
        EventDelegateVirtualTableInstance = (EventDelegateVirtualTable*) malloc(sizeof(EventDelegateVirtualTable));
        if(!EventDelegateVirtualTableInstance)
        {
            raise(SIGABRT);
        }
        EventDelegateVirtualTableInstance->TypeID = EVENTDELEGATE_TYPEID;

        EventDelegateVirtualTableInstance->Interface = (EventDelegateInterface*)malloc(sizeof(EventDelegateInterface));
        if(!EventDelegateVirtualTableInstance->Interface)
        {
            raise(SIGABRT);
        }
        EventDelegateVirtualTableInstance->Interface->Constructor = EventDelegateConstructor;
        EventDelegateVirtualTableInstance->Interface->Destructor = EventDelegateDestructor;
        EventDelegateVirtualTableInstance->Interface->Clone = EventDelegateClone;
        EventDelegateVirtualTableInstance->Interface->Handle = EventDelegateHandle;

        EventDelegateVirtualTableInstance->AncestorTable = ClassInitialize((Class*)this, pArgsCount, pParameters);

        EventDelegateVirtualTableInstance->new = EventDelegateNew;
        EventDelegateVirtualTableInstance->Initialize = EventDelegateInitialize;
        EventDelegateVirtualTableInstance->Garbage = (void (*)(EventDelegate*))EventDelegateVirtualTableInstance->AncestorTable->Garbage;
        EventDelegateVirtualTableInstance->TypeOf = (unsigned long int (*)(EventDelegate*))EventDelegateVirtualTableInstance->AncestorTable->TypeOf;
        EventDelegateVirtualTableInstance->IsSameTypeThanTypeID = (bool (*)(EventDelegate*, unsigned long int))EventDelegateVirtualTableInstance->AncestorTable->IsSameTypeThanTypeID;
        EventDelegateVirtualTableInstance->IsKindOfTypeID = (bool (*)(EventDelegate* this, unsigned long int))EventDelegateVirtualTableInstance->AncestorTable->IsKindOfTypeID;
        EventDelegateVirtualTableInstance->IsSameTypeThan = (bool (*)(EventDelegate* this, Class*))EventDelegateVirtualTableInstance->AncestorTable->IsSameTypeThan;
        EventDelegateVirtualTableInstance->IsKindOf = (bool (*)(EventDelegate* this, Class*))EventDelegateVirtualTableInstance->AncestorTable->IsKindOf;
    }
    EventDelegateVirtualTableInstance->Interface->Constructor(this, pArgsCount, pParameters);
    EventDelegateVirtualTableInstance->ReferenceCount++;
    return EventDelegateVirtualTableInstance;
}

void EventDelegateConstructor(EventDelegate* this, unsigned long int pArgsCount, va_list* pParameters)
{
    if(pArgsCount < 3)
    {
        ((ExceptionManager*)new((void*(*)(unsigned long int, va_list*))ExceptionManagerNew, 0))->throw(new((void*(*)(unsigned long int, va_list*))ExceptionNew, 1, "EventDelegate : Too few parameters for EventDelegateConstructor."));
    }
    else
    {
        this->aEvent = va_arg(*pParameters, Event*);
        if(this->aEvent == 0)
        {
            ((ExceptionManager*)new((void*(*)(unsigned long int, va_list*))ExceptionManagerNew, 0))->throw(new((void*(*)(unsigned long int, va_list*))ExceptionNew, 1, "EventDelegateConstructor : Event must exist."));
        }
        this->aObserver = va_arg(*pParameters, Class*);
        if(this->aObserver == 0)
        {
            ((ExceptionManager*)new((void*(*)(unsigned long int, va_list*))ExceptionManagerNew, 0))->throw(new((void*(*)(unsigned long int, va_list*))ExceptionNew, 1, "EventDelegateConstructor : Observer must exist."));
        }
        this->aHandler = va_arg(*pParameters, void (*)(Class* pObserver, Class* pSender, EventArgs* pEventArgs));
        if(this->aHandler == 0)
        {
            ((ExceptionManager*)new((void*(*)(unsigned long int, va_list*))ExceptionManagerNew, 0))->throw(new((void*(*)(unsigned long int, va_list*))ExceptionNew, 1, "EventDelegateConstructor : Handler must exist."));
        }
    }
}

void EventDelegateDestructor(EventDelegate* this)
{
    this->aEvent->RemoveDelegate(this->aEvent, this);
}

EventDelegate* EventDelegateClone(EventDelegate* this)
{
    return (EventDelegate*)new((void* (*)(unsigned long int, va_list*))EventDelegateNew, 2, this->aObserver, this->aHandler);
}

void EventDelegateHandle(EventDelegate* this, Class* pSender, EventArgs* pEventArgs)
{
    this->aHandler(this->aObserver, pSender, pEventArgs);
}

